package com.recharge.web.controller;


import com.alibaba.fastjson.JSON;
import com.recharge.common.enums.ErrorCode;
import com.recharge.common.result.ResultDO;
import com.recharge.common.result.web.ObjectResponse;
import com.recharge.common.util.*;
import com.recharge.domain.context.ShiroUtils;
import com.recharge.domain.query.RoleDataPermissionQueryDO;
import com.recharge.domain.vo.RoleDO;
import com.recharge.domain.vo.UserLoginDO;
import com.recharge.domain.vo.UserLoginLogDO;
import com.recharge.service.RoleDataPermissionService;
import com.recharge.service.RoleService;
import com.recharge.service.UserLoginLogService;
import com.recharge.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("/index")
@Api(value = "IndexContorller | 主页")
public class IndexContorller extends BaseController {

    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    @Autowired
    UserLoginLogService loginLogService;
	@Autowired
	RedisUtil redisUtil;
    @Autowired
    RoleService roleService;
    @Autowired
    UserService userService;
    @Autowired
    private RoleDataPermissionService roleDataPermissionService;
    @Autowired
    JwtProperties jwtProperties;

    @RequestMapping(value = "/login.html", method = RequestMethod.POST)
    @ApiOperation(value = "用户登陆", notes = "")
    public @ResponseBody
    ObjectResponse login(@RequestBody UserLoginDO domain, HttpServletRequest request, HttpServletResponse httpResponse) {

    	ObjectResponse response = new ObjectResponse();

    	int status = 1;
        String msg = "";
    	boolean flog = false;
        ResultDO result=null;
    	if(TemplateUtils.isEmpty(domain.getUsername()) || TemplateUtils.isEmpty(domain.getPassword())) {
//    		response.setStatus(Constant.UNAUTHORIZED);
    		response.setStatus(ErrorCode.USER_ACCOUNT_PASSWORD_ERROR.getCode());
    		response.setMsg("用户名或密码为空！");
        	return response;
        }
		String salt = ByteSource.Util.bytes(domain.getUsername()).toHex();
		String password = PasswordUtil.getPassword(domain.getPassword(), salt);

        Subject currentUser = SecurityUtils.getSubject();
        // 如果这个用户没有登录,进行登录功能
        if( !currentUser.isAuthenticated() ) {
            try{
                // 验证身份和登陆
                UsernamePasswordToken token = new UsernamePasswordToken(domain.getUsername(), domain.getPassword());
                currentUser.login(token);
            }catch (UnknownAccountException e) {
                response.setStatus(ErrorCode.SYSTEM_EXCEPTION.getCode());
                response.setMsg("未知账户！");
                return response;
            } catch (IncorrectCredentialsException e) {
                response.setStatus(ErrorCode.USER_ACCOUNT_PASSWORD_ERROR.getCode());
//                msg = "密码不正确";
                msg = ErrorCode.USER_ACCOUNT_PASSWORD_ERROR.getMsg();
                status = 0;
            } catch (LockedAccountException e) {
                response.setStatus(ErrorCode.SYSTEM_EXCEPTION.getCode());
                msg = "账户已锁定";
                status = 2;
            } catch (ExcessiveAttemptsException eae) {
                response.setStatus(ErrorCode.SYSTEM_EXCEPTION.getCode());
                msg = "用户名或密码错误次数过多";
            } catch (AuthenticationException e) {
                response.setStatus(ErrorCode.UNAUTHORIZED_EXCEPTION.getCode());
                msg = "未知错误!";
            }
        }
        String token = SecurityUtils.getSubject().getSession().getId().toString();;
        String currentTimeMillis = String.valueOf(System.currentTimeMillis());
		logger.debug("用户名：" + domain.getUsername() + " 第一次登陆记录登陆日志");
        UserLoginDO loginDO = (UserLoginDO) redisUtil.get(Constant.USER + domain.getUsername());
        /*result = roleService.getRoleIdsByUserId(ShiroUtils.getUserInfo().getId());
        if(result.getModel(ResultDO.FIRST_MODEL_KEY)!=null){
            List<String> roleIdList =(List<String>) result.getModel(ResultDO.FIRST_MODEL_KEY);
            //登录时将权限白名单存入redis
            if(roleIdList!=null&&roleIdList.size()>0){
                RoleDataPermissionQueryDO roleDataPermissionQueryDO = new RoleDataPermissionQueryDO();
                String roleIds = "";
                for (String roleDO:roleIdList){
                    roleIds+=","+roleDO;
                }
                roleIds=roleIds.substring(1);
                roleDataPermissionQueryDO.setTableName("business_order");
                roleDataPermissionQueryDO.setRoleIds(roleIds.split(","));
                //获取权限允许字段
                List<Map<String,Object>> map = roleDataPermissionService.getPermissionField(roleDataPermissionQueryDO);
                //获取所有字段包括额外字段
                //ResultDO resultDO = roleDataPermissionService.findField(roleDataPermissionQueryDO);
                Map<String,List<String>> roleTable = new HashMap<>();
                for (Map<String,Object> m : map) {
                    if(roleTable.containsKey(m.get("tableName").toString())){
                        List<String> templist = roleTable.get(m.get("tableName").toString());
                        templist.add(m.get("tableField").toString());
                        roleTable.put(m.get("tableName").toString(),templist);
                    }else{
                        List<String> templist = new ArrayList<>();
                        templist.add(m.get("tableField").toString());
                        roleTable.put(m.get("tableName").toString(),templist);
                    }
                }
                redisUtil.set(Constant.USER+token,ShiroUtils.getUserInfo());
                redisUtil.set(Constant.ROLE_DATA_PERMISSION+ShiroUtils.getUserInfo().getId(),JSON.toJSONString(roleTable) );
            }
        }*/

        if(loginDO != null){
            domain.setId(loginDO.getId());
        }
        result = addUserLoginLog(domain, request.getRemoteAddr(), status);
		if (!result.isSuccess()) {
		    logger.debug("用户名：" + domain.getUsername() + " 登陆日志记录失败");
            response.setStatus(result.getErrorCode().getCode());
		    response.setMsg(result.getErrorCode().getMsg());
		    return response;
		}
		//设置token
		if (response.getStatus() == Constant.HTTP_SUCCESS) {
//            String tokenKey=Constant.PREFIX_SHIRO_CACHE + token;
//            redisUtil.set(tokenKey, token, jwtProperties.getTokenExpireTime()*60*60l);
//            String refreshTokenKey= Constant.PREFIX_SHIRO_REFRESH_TOKEN + domain.getUsername();
//            redisUtil.set(refreshTokenKey, currentTimeMillis, jwtProperties.getRefreshTokenExpireTime()*60*60l);
	        //写入header
	        httpResponse.setHeader(Constant.AUTH_TOKEN, token);
	        httpResponse.setHeader("Access-Control-Expose-Headers", Constant.AUTH_TOKEN);
		}
        UserLoginDO user = getUserLoginInfo();
		response.setData(user);
        response.setMsg(msg);
		return response;
    }

    @RequestMapping(value = "/logOut.html", method = RequestMethod.POST)
    @ApiOperation(value = "用户退出登陆", notes = "")
    public @ResponseBody
    ObjectResponse logOut() {
        ObjectResponse response = new ObjectResponse();
        SecurityUtils.getSubject().logout();
        response.setMsg("用户退出登陆");
        return response;
    }

    private ResultDO addUserLoginLog(UserLoginDO domain, String requestIP, int status) {
        // 登录日志对象
        UserLoginLogDO loginLogDO = new UserLoginLogDO();

        loginLogDO.setUsername(domain.getUsername());
        loginLogDO.setIpAddress(requestIP);
        loginLogDO.setUserId(domain.getId());
        loginLogDO.setStatus(status);
        ResultDO result = loginLogService.add(loginLogDO);
        return result;
    }
}